package com.th.coupon.executor;

import com.th.coupon.common.constant.CouponCategory;
import com.th.coupon.common.exception.BaseCloudException;
import com.th.coupon.common.vo.SettlementInfo;
import com.th.coupon.common.vo.response.ExceptionResultData;
import com.th.coupon.constant.RuleFlag;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.stereotype.Component;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 优惠卷规则执行器管理器
 *  根据用户的请求找到对应的Execute,去做结算
 *  {@link BeanPostProcessor} bean的后置处理器
 *  @author 涂航
 */
@Component
@Slf4j
public class ExecuteManager implements BeanPostProcessor {

    /**
     * 规则执行器映射
     */
    private static Map<RuleFlag,RuleExecutor> executorIndex =
            new HashMap<>(RuleFlag.values().length);

    /**
     * 优惠卷结算规则计算入口
     *  保证传递进来的优惠卷数量 > 1
     * @param settlementInfo
     * @return
     * @throws BaseCloudException
     */
    public SettlementInfo computeRule(SettlementInfo settlementInfo) throws BaseCloudException {
        SettlementInfo result = null;
        //单类优惠卷
        if(settlementInfo.getCouponAndTemplateInfos().size() == 1){
            //获取优惠卷的类别
            CouponCategory category = CouponCategory.of(
                    settlementInfo.getCouponAndTemplateInfos().get(0).getTemplateSdk()
                            .getCategory()
            );
            switch (category){
                case ALLMINUS:
                    result = executorIndex.get(RuleFlag.ALLMINUS_RULE).computeRule(settlementInfo);
                    break;
                case DISCOUNT:
                    result = executorIndex.get(RuleFlag.DISCOUNT_RULE).computeRule(settlementInfo);
                    break;
                case SETUPMINUS:
                    result = executorIndex.get(RuleFlag.SETUPMINUS_RULE).computeRule(settlementInfo);
                    break;
            }
        }else {
            List<CouponCategory> categories = new ArrayList<>(
                    settlementInfo.getCouponAndTemplateInfos().size()
            );
            settlementInfo.getCouponAndTemplateInfos().forEach(couponAndTemplateInfo ->
                categories.add(CouponCategory.of(couponAndTemplateInfo
                        .getTemplateSdk().getCategory())));
            if(categories.size() != 2){
                throw new BaseCloudException(ExceptionResultData.NOT_SUPPORT_TEMPLATE_CATEGORY);
            }else {
                //如果优惠卷分别为满减和折扣
                if(categories.contains(CouponCategory.ALLMINUS) &&
                categories.contains(CouponCategory.DISCOUNT)){
                    result = executorIndex.get(RuleFlag.ALLMINUS_DISCOUNT_RULE).computeRule(settlementInfo);
                }else {
                    throw new BaseCloudException(ExceptionResultData.NOT_SUPPORT_TEMPLATE_CATEGORY);
                }
            }
        }
        return result;
    }

    /**
     * 在bean初始化之前去执行
     * @param bean
     * @param beanName
     * @return
     * @throws BeansException
     */
    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName)
            throws BeansException {
        if(!(bean instanceof RuleExecutor)){
            return bean;
        }
        RuleExecutor executor = (RuleExecutor)bean;
        RuleFlag ruleFlag = executor.ruleConfig();

        if(executorIndex.containsKey(ruleFlag)){
            throw new IllegalStateException("There is already on executor for rule flag :" +ruleFlag);
        }
        log.info("Load Executor {} for rule Flag {}",executor.getClass(),ruleFlag);
        executorIndex.put(ruleFlag,executor);

        return null;
    }

    /**
     * 在bean初始化之后去执行
     * @param bean
     * @param beanName
     * @return
     * @throws BeansException
     */
    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName)
            throws BeansException {
        return bean;
    }
}
